package com.example.wzviewer.util;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.OpenableColumns;

import com.arthenica.ffmpegkit.FFprobeKit;
import com.arthenica.ffmpegkit.ReturnCode;
import com.arthenica.ffmpegkit.Session;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/** 只获取：视频名称 + 分辨率（width/height），对 asset:// 做强制缓存拷贝兜底。 */
public final class FfprobeLite {
    private FfprobeLite(){}

    public static class Result {
        public String name = "-";
        public int width = 0;
        public int height = 0;
    }
    public interface Callback {
        void onSuccess(Result r);
        void onError(String msg); // 返回详细错误
    }

    private static final ExecutorService EXEC = Executors.newSingleThreadExecutor();

    /*public static void probeNameAndSize(Context ctx, Uri uri, Callback cb) {
        EXEC.execute(() -> {
            String scheme = uri.getScheme() == null ? "" : uri.getScheme().toLowerCase();
            try {
                if ("asset".equals(scheme)) {
                    // ★ 对 asset 源：直接拷贝到缓存再跑 ffprobe（最稳）
                    String cached = copyAssetToCache(ctx, uri);
                    if (cached == null) {
                        cb.onError("无法从 assets 读取该资源（可能路径不对或文件不存在）");
                        return;
                    }
                    String err = runOnce(ctx, uri, cached, cb);
                    if (err != null) cb.onError("ffprobe失败（asset缓存）：\n" + err);
                    return;
                }

                // 非 asset：先走 fd，再失败时拷贝兜底
                try (UriToFdPath.FdHandle h = UriToFdPath.toFdPath(ctx, uri)) {
                    String err = runOnce(ctx, uri, h.path, cb);
                    if (err == null) return; // 成功

                    String cached = copyUriToCache(ctx, uri);
                    if (cached != null) {
                        String err2 = runOnce(ctx, uri, cached, cb);
                        if (err2 == null) return; // 成功
                        cb.onError("ffprobe失败（fd与缓存皆失败）：\n" + err + "\n---\n" + err2);
                    } else {
                        cb.onError("ffprobe失败（fd失败，且无法创建缓存文件）：\n" + err);
                    }
                }
            } catch (Exception e) {
                cb.onError("probe异常：" + e.getMessage());
            }
        });
    }
*/

    //方法开头判断协议为 http/https 时，直接把 URL 传给 ffprobe，不要走 fd 或缓存拷贝
    public static void probeNameAndSize(Context ctx, Uri uri, Callback cb) {
        EXEC.execute(() -> {
            String scheme = uri.getScheme() == null ? "" : uri.getScheme().toLowerCase();
            try {
                // 直接用网络 URL
                if ("http".equals(scheme) || "https".equals(scheme)) {
                    String err = runOnce(ctx, uri, uri.toString(), cb); // 直接传 URL
                    if (err != null) cb.onError("ffprobe失败（网络URL）：\n" + err);
                    return;
                }

                if ("asset".equals(scheme)) {
                    String cached = copyAssetToCache(ctx, uri);
                    if (cached == null) { cb.onError("无法从 assets 读取该资源"); return; }
                    String err = runOnce(ctx, uri, cached, cb);
                    if (err != null) cb.onError("ffprobe失败（asset缓存）：\n" + err);
                    return;
                }

                // content:// 或 file://（或无 scheme 的绝对路径）
                try (UriToFdPath.FdHandle h = UriToFdPath.toFdPath(ctx, uri)) {
                    String err = runOnce(ctx, uri, h.path, cb);
                    if (err == null) return;
                    String cached = copyUriToCache(ctx, uri);
                    if (cached != null) {
                        String err2 = runOnce(ctx, uri, cached, cb);
                        if (err2 == null) return;
                        cb.onError("ffprobe失败（fd与缓存皆失败）：\n" + err + "\n---\n" + err2);
                    } else {
                        cb.onError("ffprobe失败（fd失败，且无法创建缓存文件）：\n" + err);
                    }
                }
            } catch (Exception e) {
                cb.onError("probe异常：" + e.getMessage());
            }
        });
    }

    /** 单次执行：返回 null 表成功；否则返回错误详情 */
    private static String runOnce(Context ctx, Uri uri, String inputPath, Callback cb) {
        String cmd = String.format(Locale.US,
                "-v error -select_streams v:0 " +
                        "-show_entries stream=width,height " +
                        "-of default=noprint_wrappers=1:nokey=0 " +
                        "-i \"%s\"", inputPath);

        Session session = FFprobeKit.execute(cmd);
        if (!ReturnCode.isSuccess(session.getReturnCode())) {
            return session.getAllLogsAsString();
        }
        String out = session.getOutput();
        Result r = parseToResult(ctx, uri, out);
        cb.onSuccess(r);
        return null;
    }

    private static Result parseToResult(Context ctx, Uri uri, String text) {
        Result r = new Result();
        r.name = displayName(ctx, uri);
        String[] lines = text.split("\n");
        for (String line : lines) {
            String[] kv = line.trim().split("=", 2);
            if (kv.length != 2) continue;
            if ("width".equals(kv[0]))  r.width  = safeInt(kv[1]);
            if ("height".equals(kv[0])) r.height = safeInt(kv[1]);
        }
        return r;
    }

    private static int safeInt(String s) { try { return Integer.parseInt(s); } catch (Exception e) { return 0; } }

    private static String displayName(Context ctx, Uri uri) {
        if ("content".equalsIgnoreCase(String.valueOf(uri.getScheme()))) {
            ContentResolver cr = ctx.getContentResolver();
            try (Cursor c = cr.query(uri, new String[]{OpenableColumns.DISPLAY_NAME}, null, null, null)) {
                if (c != null && c.moveToFirst()) return c.getString(0);
            } catch (Exception ignore) {}
        }
        String s = uri.getLastPathSegment();
        if (s == null) s = uri.toString();
        int i = s.lastIndexOf('/');
        return i>=0 ? s.substring(i+1) : s;
    }

    /** 将 asset:///相对路径 拷贝到缓存目录，返回绝对路径；失败返回 null */
    private static String copyAssetToCache(Context ctx, Uri uri) {
        String rel = uri.toString().replaceFirst("^asset:///+", ""); // e.g. "video/720p_2.mp4"
        File tmp = null;
        try (InputStream is = ctx.getAssets().open(rel)) {
            String name = "ffp_asset_" + System.currentTimeMillis() + guessExt(rel);
            tmp = new File(ctx.getCacheDir(), name);
            try (FileOutputStream os = new FileOutputStream(tmp)) {
                byte[] buf = new byte[8192];
                int n; while ((n = is.read(buf)) > 0) os.write(buf, 0, n);
            }
            return tmp.getAbsolutePath();
        } catch (Exception e) {
            if (tmp != null) try { tmp.delete(); } catch (Exception ignore) {}
            return null;
        }
    }

    /** 将任意 Uri（content:// 或 file://）拷贝到缓存；失败返回 null */
    private static String copyUriToCache(Context ctx, Uri uri) {
        File tmp = null;
        try (InputStream is = ctx.getContentResolver().openInputStream(uri)) {
            if (is == null) return null;
            String name = "ffp_cache_" + System.currentTimeMillis() + guessExt(String.valueOf(uri));
            tmp = new File(ctx.getCacheDir(), name);
            try (FileOutputStream os = new FileOutputStream(tmp)) {
                byte[] buf = new byte[8192];
                int n; while ((n = is.read(buf)) > 0) os.write(buf, 0, n);
            }
            return tmp.getAbsolutePath();
        } catch (Exception e) {
            if (tmp != null) try { tmp.delete(); } catch (Exception ignore) {}
            return null;
        }
    }

    /** 根据路径猜扩展名（仅为调试友好，非必须） */
    private static String guessExt(String path) {
        int i = path.lastIndexOf('.');
        if (i > 0 && i < path.length()-1) return path.substring(i);
        return ".bin";
    }
}
